home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / shllutil.lha / shellutils-1.8 / src / stty.c < prev    next >
C/C++ Source or Header  |  1992-10-28  |  28KB  |  1,242 lines

  1. /* stty -- change and print terminal line settings
  2.    Copyright (C) 1990, 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Usage: stty [-ag] [--all] [--save] [setting...]
  19.  
  20.    Options:
  21.    -a, --all    Write all current settings to stdout in human-readable form.
  22.    -g, --save    Write all current settings to stdout in stty-readable form.
  23.  
  24.    If no args are given, write to stdout the baud rate and settings that
  25.    have been changed from their defaults.  Mode reading and changes
  26.    are done on stdin.
  27.  
  28.    David MacKenzie <djm@gnu.ai.mit.edu> */
  29.  
  30. #include <stdio.h>
  31. #include <sys/types.h>
  32. #include <termios.h>
  33. #ifdef _AIX
  34. #include <sys/ioctl.h>        /* Needed to get window size. */
  35. #endif
  36. #ifdef WINSIZE_IN_PTEM
  37. #include <sys/stream.h>
  38. #include <sys/ptem.h>
  39. #endif
  40. #include <getopt.h>
  41. #ifdef __STDC__
  42. #include <stdarg.h>
  43. #define VA_START(args, lastarg) va_start(args, lastarg)
  44. #else
  45. #include <varargs.h>
  46. #define VA_START(args, lastarg) va_start(args)
  47. #endif
  48. #include "system.h"
  49.  
  50. #if defined(GWINSZ_BROKEN)    /* Such as for SCO UNIX 3.2.2. */
  51. #undef TIOCGWINSZ
  52. #endif
  53.  
  54. #ifndef _POSIX_VDISABLE
  55. #define _POSIX_VDISABLE ((unsigned char) 0)
  56. #endif
  57.  
  58. #define    Control(c) ((c) & 0x1f)
  59. /* Canonical values for control characters. */
  60. #ifndef CINTR
  61. #define    CINTR Control ('c')
  62. #endif
  63. #ifndef CQUIT
  64. #define    CQUIT 28
  65. #endif
  66. #ifndef CERASE
  67. #define    CERASE 127
  68. #endif
  69. #ifndef CKILL
  70. #define    CKILL Control ('u')
  71. #endif
  72. #ifndef CEOF
  73. #define    CEOF Control ('d')
  74. #endif
  75. #ifndef CEOL
  76. #define    CEOL _POSIX_VDISABLE
  77. #endif
  78. #ifndef CSTART
  79. #define    CSTART Control ('q')
  80. #endif
  81. #ifndef CSTOP
  82. #define    CSTOP Control ('s')
  83. #endif
  84. #ifndef CSUSP
  85. #define    CSUSP Control ('z')
  86. #endif
  87. #if defined(VEOL2) && !defined(CEOL2)
  88. #define    CEOL2 _POSIX_VDISABLE
  89. #endif
  90. #if defined(VSWTCH) && !defined(CSWTCH)
  91. #define    CSWTCH _POSIX_VDISABLE
  92. #endif
  93. #if defined(VDSUSP) && !defined (CDSUSP)
  94. #define    CDSUSP Control ('y')
  95. #endif
  96. #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
  97. #define VREPRINT VRPRNT
  98. #endif
  99. #if defined(VREPRINT) && !defined(CRPRNT)
  100. #define    CRPRNT Control ('r')
  101. #endif
  102. #if defined(VWERASE) && !defined(CWERASE)
  103. #define    CWERASE Control ('w')
  104. #endif
  105. #if defined(VLNEXT) && !defined(CLNEXT)
  106. #define    CLNEXT Control ('v')
  107. #endif
  108.  
  109. char *visible ();
  110. unsigned long baud_to_value ();
  111. int recover_mode ();
  112. int screen_columns ();
  113. int set_mode ();
  114. long integer_arg ();
  115. speed_t string_to_baud ();
  116. tcflag_t *mode_type_flag ();
  117. void display_all ();
  118. void display_changed ();
  119. void display_recoverable ();
  120. void display_settings ();
  121. void display_speed ();
  122. void display_window_size ();
  123. void error ();
  124. void sane_mode ();
  125. void set_control_char ();
  126. void set_speed ();
  127. void set_window_size ();
  128.  
  129. /* Which speeds to set.  */
  130. enum speed_setting
  131. {
  132.   input_speed, output_speed, both_speeds
  133. };
  134.  
  135. /* What to output and how.  */
  136. enum output_type
  137. {
  138.   changed, all, recoverable    /* Default, -a, -g.  */
  139. };
  140.  
  141. /* Which member(s) of `struct termios' a mode uses.  */
  142. enum mode_type
  143. {
  144.   control, input, output, local, combination
  145. };
  146.  
  147. /* Flags for `struct mode_info'. */
  148. #define SANE_SET 1        /* Set in `sane' mode. */
  149. #define SANE_UNSET 2        /* Unset in `sane' mode. */
  150. #define REV 4            /* Can be turned off by prepending `-'. */
  151. #define OMIT 8            /* Don't display value. */
  152.  
  153. /* Each mode.  */
  154. struct mode_info
  155. {
  156.   char *name;            /* Name given on command line.  */
  157.   enum mode_type type;        /* Which structure element to change. */
  158.   char flags;            /* Setting and display options.  */
  159.   unsigned long bits;        /* Bits to set for this mode.  */
  160.   unsigned long mask;        /* Other bits to turn off for this mode.  */
  161. };
  162.  
  163. struct mode_info mode_info[] =
  164. {
  165.   {"parenb", control, REV, PARENB, 0},
  166.   {"parodd", control, REV, PARODD, 0},
  167.   {"cs5", control, 0, CS5, CSIZE},
  168.   {"cs6", control, 0, CS6, CSIZE},
  169.   {"cs7", control, 0, CS7, CSIZE},
  170.   {"cs8", control, 0, CS8, CSIZE},
  171.   {"hupcl", control, REV, HUPCL, 0},
  172.   {"hup", control, REV | OMIT, HUPCL, 0},
  173.   {"cstopb", control, REV, CSTOPB, 0},
  174.   {"cread", control, SANE_SET | REV, CREAD, 0},
  175.   {"clocal", control, REV, CLOCAL, 0},
  176. #ifdef CRTSCTS
  177.   {"crtscts", control, REV, CRTSCTS, 0},
  178. #endif
  179.  
  180.   {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
  181.   {"brkint", input, SANE_SET | REV, BRKINT, 0},
  182.   {"ignpar", input, REV, IGNPAR, 0},
  183.   {"parmrk", input, REV, PARMRK, 0},
  184.   {"inpck", input, REV, INPCK, 0},
  185.   {"istrip", input, REV, ISTRIP, 0},
  186.   {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
  187.   {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
  188.   {"icrnl", input, SANE_SET | REV, ICRNL, 0},
  189.   {"ixon", input, REV, IXON, 0},
  190.   {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
  191.   {"tandem", input, REV | OMIT, IXOFF, 0},
  192. #ifdef IUCLC
  193.   {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
  194. #endif
  195. #ifdef IXANY
  196.   {"ixany", input, SANE_UNSET | REV, IXANY, 0},
  197. #endif
  198. #ifdef IMAXBEL
  199.   {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
  200. #endif
  201.  
  202.   {"opost", output, SANE_SET | REV, OPOST, 0},
  203. #ifdef OLCUC
  204.   {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
  205. #endif
  206. #ifdef OCRNL
  207.   {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
  208. #endif
  209. #ifdef ONLCR
  210.   {"onlcr", output, SANE_SET | REV, ONLCR, 0},
  211. #endif
  212. #ifdef ONOCR
  213.   {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
  214. #endif
  215. #ifdef ONLRET
  216.   {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
  217. #endif
  218. #ifdef OFILL
  219.   {"ofill", output, SANE_UNSET | REV, OFILL, 0},
  220. #endif
  221. #ifdef OFDEL
  222.   {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
  223. #endif
  224. #ifdef NLDLY
  225.   {"nl1", output, SANE_UNSET, NL1, NLDLY},
  226.   {"nl0", output, SANE_SET, NL0, NLDLY},
  227. #endif
  228. #ifdef CRDLY
  229.   {"cr3", output, SANE_UNSET, CR3, CRDLY},
  230.   {"cr2", output, SANE_UNSET, CR2, CRDLY},
  231.   {"cr1", output, SANE_UNSET, CR1, CRDLY},
  232.   {"cr0", output, SANE_SET, CR0, CRDLY},
  233. #endif
  234. #ifdef TABDLY
  235.   {"tab3", output, SANE_UNSET, TAB3, TABDLY},
  236.   {"tab2", output, SANE_UNSET, TAB2, TABDLY},
  237.   {"tab1", output, SANE_UNSET, TAB1, TABDLY},
  238.   {"tab0", output, SANE_SET, TAB0, TABDLY},
  239. #endif
  240. #ifdef BSDLY
  241.   {"bs1", output, SANE_UNSET, BS1, BSDLY},
  242.   {"bs0", output, SANE_SET, BS0, BSDLY},
  243. #endif
  244. #ifdef VTDLY
  245.   {"vt1", output, SANE_UNSET, VT1, VTDLY},
  246.   {"vt0", output, SANE_SET, VT0, VTDLY},
  247. #endif
  248. #ifdef FFDLY
  249.   {"ff1", output, SANE_UNSET, FF1, FFDLY},
  250.   {"ff0", output, SANE_SET, FF0, FFDLY},
  251. #endif
  252.  
  253.   {"isig", local, SANE_SET | REV, ISIG, 0},
  254.   {"icanon", local, SANE_SET | REV, ICANON, 0},
  255. #ifdef IEXTEN
  256.   {"iexten", local, SANE_SET | REV, IEXTEN, 0},
  257. #endif
  258.   {"echo", local, SANE_SET | REV, ECHO, 0},
  259.   {"echoe", local, SANE_SET | REV, ECHOE, 0},
  260.   {"crterase", local, REV | OMIT, ECHOE, 0},
  261.   {"echok", local, SANE_SET | REV, ECHOK, 0},
  262.   {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
  263.   {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
  264. #ifdef XCASE
  265.   {"xcase", local, SANE_UNSET | REV, XCASE, 0},
  266. #endif
  267. #ifdef TOSTOP
  268.   {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
  269. #endif
  270. #ifdef ECHOPRT
  271.   {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
  272.   {"prterase", local, REV | OMIT, ECHOPRT, 0},
  273. #endif
  274. #ifdef ECHOCTL
  275.   {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
  276.   {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
  277. #endif
  278. #ifdef ECHOKE
  279.   {"echoke", local, SANE_SET | REV, ECHOKE, 0},
  280.   {"crtkill", local, REV | OMIT, ECHOKE, 0},
  281. #endif
  282.  
  283.   {"evenp", combination, REV | OMIT, 0, 0},
  284.   {"parity", combination, REV | OMIT, 0, 0},
  285.   {"oddp", combination, REV | OMIT, 0, 0},
  286.   {"nl", combination, REV | OMIT, 0, 0},
  287.   {"ek", combination, OMIT, 0, 0},
  288.   {"sane", combination, OMIT, 0, 0},
  289.   {"cooked", combination, REV | OMIT, 0, 0},
  290.   {"raw", combination, REV | OMIT, 0, 0},
  291.   {"pass8", combination, REV | OMIT, 0, 0},
  292.   {"litout", combination, REV | OMIT, 0, 0},
  293.   {"cbreak", combination, REV | OMIT, 0, 0},
  294. #ifdef IXANY
  295.   {"decctlq", combination, REV | OMIT, 0, 0},
  296. #endif
  297. #ifdef TABDLY
  298.   {"tabs", combination, REV | OMIT, 0, 0},
  299. #endif
  300. #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
  301.   {"lcase", combination, REV | OMIT, 0, 0},
  302.   {"LCASE", combination, REV | OMIT, 0, 0},
  303. #endif
  304.   {"crt", combination, OMIT, 0, 0},
  305.   {"dec", combination, OMIT, 0, 0},
  306.  
  307.   {NULL, control, 0, 0, 0}
  308. };
  309.  
  310. /* Control character settings.  */
  311. struct control_info
  312. {
  313.   char *name;            /* Name given on command line.  */
  314.   unsigned char saneval;    /* Value to set for `stty sane'.  */
  315.   int offset;            /* Offset in c_cc.  */
  316. };
  317.  
  318. /* Control characters. */
  319.  
  320. struct control_info control_info[] =
  321. {
  322.   {"intr", CINTR, VINTR},
  323.   {"quit", CQUIT, VQUIT},
  324.   {"erase", CERASE, VERASE},
  325.   {"kill", CKILL, VKILL},
  326.   {"eof", CEOF, VEOF},
  327.   {"eol", CEOL, VEOL},
  328. #ifdef VEOL2
  329.   {"eol2", CEOL2, VEOL2},
  330. #endif
  331. #ifdef VSWTCH
  332.   {"swtch", CSWTCH, VSWTCH},
  333. #endif
  334.   {"start", CSTART, VSTART},
  335.   {"stop", CSTOP, VSTOP},
  336.   {"susp", CSUSP, VSUSP},
  337. #ifdef VDSUSP
  338.   {"dsusp", CDSUSP, VDSUSP},
  339. #endif
  340. #ifdef VREPRINT
  341.   {"rprnt", CRPRNT, VREPRINT},
  342. #endif
  343. #ifdef VWERASE
  344.   {"werase", CWERASE, VWERASE},
  345. #endif
  346. #ifdef VLNEXT
  347.   {"lnext", CLNEXT, VLNEXT},
  348. #endif
  349.  
  350.   /* These must be last because of the display routines. */
  351.   {"min", 1, VMIN},
  352.   {"time", 0, VTIME},
  353.   {NULL, 0, 0}
  354. };
  355.  
  356. /* The width of the screen, for output wrapping. */
  357. int max_col;
  358.  
  359. /* Current position, to know when to wrap. */
  360. int current_col;
  361.  
  362. struct option longopts[] =
  363. {
  364.   {"all", 0, NULL, 'a'},
  365.   {"save", 0, NULL, 'g'},
  366.   {NULL, 0, NULL, 0}
  367. };
  368.  
  369. /* The name this program was run with. */
  370. char *program_name;
  371.  
  372. /* Print format string MESSAGE and optional args.
  373.    Wrap to next line first if it won't fit.
  374.    Print a space first unless MESSAGE will start a new line. */
  375.  
  376. /* VARARGS */
  377. void
  378. #ifdef __STDC__
  379. wrapf (char *message, ...)
  380. #else
  381. wrapf (message, va_alist)
  382.      char *message;
  383.      va_dcl
  384. #endif
  385. {
  386.   va_list args;
  387.   char buf[1024];        /* Plenty long for our needs. */
  388.   int buflen;
  389.  
  390.   VA_START (args, message);
  391.   vsprintf (buf, message, args);
  392.   va_end (args);
  393.   buflen = strlen (buf);
  394.   if (current_col + buflen >= max_col)
  395.     {
  396.       putchar ('\n');
  397.       current_col = 0;
  398.     }
  399.   if (current_col > 0)
  400.     {
  401.       putchar (' ');
  402.       current_col++;
  403.     }
  404.   fputs (buf, stdout);
  405.   current_col += buflen;
  406. }
  407.  
  408. void
  409. main (argc, argv)
  410.      int argc;
  411.      char **argv;
  412. {
  413.   struct termios mode;
  414.   enum output_type output_type = changed;
  415.   int optc;
  416.  
  417.   program_name = argv[0];
  418.   opterr = 0;
  419.  
  420.   while ((optc = getopt_long (argc, argv, "ag", longopts, (int *) 0)) != EOF)
  421.     {
  422.       if (optc == 'a')
  423.     output_type = all;
  424.       else if (optc == 'g')
  425.     output_type = recoverable;
  426.       else
  427.     break;
  428.     }
  429.  
  430.   if (tcgetattr (0, &mode))
  431.     error (1, errno, "standard input");
  432.  
  433.   max_col = screen_columns ();
  434.   current_col = 0;
  435.  
  436.   if (optind == argc)
  437.     {
  438.       if (optc == '?')
  439.     error (1, 0, "invalid argument `%s'", argv[--optind]);
  440.       display_settings (output_type, &mode);
  441.       exit (0);
  442.     }
  443.  
  444.   while (optind < argc)
  445.     {
  446.       int match_found = 0;
  447.       int reversed = 0;
  448.       int i;
  449.  
  450.       if (argv[optind][0] == '-')
  451.     {
  452.       ++argv[optind];
  453.       reversed = 1;
  454.     }
  455.       for (i = 0; mode_info[i].name != NULL; ++i)
  456.     {
  457.       if (!strcmp (argv[optind], mode_info[i].name))
  458.         {
  459.           match_found = set_mode (&mode_info[i], reversed, &mode);
  460.           break;
  461.         }
  462.     }
  463.       if (match_found == 0 && reversed)
  464.     error (1, 0, "invalid argument `%s'", --argv[optind]);
  465.       if (match_found == 0)
  466.     {
  467.       for (i = 0; control_info[i].name != NULL; ++i)
  468.         {
  469.           if (!strcmp (argv[optind], control_info[i].name))
  470.         {
  471.           if (optind == argc - 1)
  472.             error (1, 0, "missing argument to `%s'", argv[optind]);
  473.           match_found = 1;
  474.           ++optind;
  475.           set_control_char (&control_info[i], argv[optind], &mode);
  476.           break;
  477.         }
  478.         }
  479.     }
  480.       if (match_found == 0)
  481.     {
  482.       if (!strcmp (argv[optind], "ispeed"))
  483.         {
  484.           if (optind == argc - 1)
  485.         error (1, 0, "missing argument to `%s'", argv[optind]);
  486.           ++optind;
  487.           set_speed (input_speed, argv[optind], &mode);
  488.         }
  489.       else if (!strcmp (argv[optind], "ospeed"))
  490.         {
  491.           if (optind == argc - 1)
  492.         error (1, 0, "missing argument to `%s'", argv[optind]);
  493.           ++optind;
  494.           set_speed (output_speed, argv[optind], &mode);
  495.         }
  496. #ifdef TIOCGWINSZ
  497.       else if (!strcmp (argv[optind], "rows"))
  498.         {
  499.           if (optind == argc - 1)
  500.         error (1, 0, "missing argument to `%s'", argv[optind]);
  501.           ++optind;
  502.           set_window_size ((int) integer_arg (argv[optind]), -1);
  503.         }
  504.       else if (!strcmp (argv[optind], "cols")
  505.            || !strcmp (argv[optind], "columns"))
  506.         {
  507.           if (optind == argc - 1)
  508.         error (1, 0, "missing argument to `%s'", argv[optind]);
  509.           ++optind;
  510.           set_window_size (-1, (int) integer_arg (argv[optind]));
  511.         }
  512.       else if (!strcmp (argv[optind], "size"))
  513.         display_window_size (0);
  514. #endif
  515. #ifdef HAVE_C_LINE
  516.       else if (!strcmp (argv[optind], "line"))
  517.         {
  518.           if (optind == argc - 1)
  519.         error (1, 0, "missing argument to `%s'", argv[optind]);
  520.           ++optind;
  521.           mode.c_line = integer_arg (argv[optind]);
  522.         }
  523. #endif
  524.       else if (!strcmp (argv[optind], "speed"))
  525.         display_speed (&mode, 0);
  526.       else if (string_to_baud (argv[optind]) != (speed_t) -1)
  527.         set_speed (both_speeds, argv[optind], &mode);
  528.       else if (recover_mode (argv[optind], &mode) == 0)
  529.         error (1, 0, "invalid argument `%s'", argv[optind]);
  530.     }
  531.       optind++;
  532.     }
  533.  
  534.   if (tcsetattr (0, TCSADRAIN, &mode))
  535.     error (1, errno, "standard input");
  536.  
  537.   exit (0);
  538. }
  539.  
  540. /* Return 0 if not applied because not reversible; otherwise return 1. */
  541.  
  542. int
  543. set_mode (info, reversed, mode)
  544.      struct mode_info *info;
  545.      int reversed;
  546.      struct termios *mode;
  547. {
  548.   tcflag_t *bitsp;
  549.  
  550.   if (reversed && (info->flags & REV) == 0)
  551.     return 0;
  552.  
  553.   bitsp = mode_type_flag (info->type, mode);
  554.  
  555.   if (bitsp == NULL)
  556.     {
  557.       /* Combination mode. */
  558.       if (!strcmp (info->name, "evenp") || !strcmp (info->name, "parity"))
  559.     {
  560.       if (reversed)
  561.         mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  562.       else
  563.         mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
  564.     }
  565.       else if (!strcmp (info->name, "oddp"))
  566.     {
  567.       if (reversed)
  568.         mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  569.       else
  570.         mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
  571.     }
  572.       else if (!strcmp (info->name, "nl"))
  573.     {
  574.       if (reversed)
  575.         {
  576.           mode->c_iflag = mode->c_iflag | ICRNL & ~INLCR & ~IGNCR;
  577.           mode->c_oflag = mode->c_oflag
  578. #ifdef ONLCR
  579.         | ONLCR
  580. #endif
  581. #ifdef OCRNL
  582.           & ~OCRNL
  583. #endif
  584. #ifdef ONLRET
  585.           & ~ONLRET
  586. #endif
  587.             ;
  588.         }
  589.       else
  590.         {
  591.           mode->c_iflag = mode->c_iflag & ~ICRNL;
  592. #ifdef ONLCR
  593.           mode->c_oflag = mode->c_oflag & ~ONLCR;
  594. #endif
  595.         }
  596.     }
  597.       else if (!strcmp (info->name, "ek"))
  598.     {
  599.       mode->c_cc[VERASE] = CERASE;
  600.       mode->c_cc[VKILL] = CKILL;
  601.     }
  602.       else if (!strcmp (info->name, "sane"))
  603.     sane_mode (mode);
  604.       else if (!strcmp (info->name, "cbreak"))
  605.     {
  606.       if (reversed)
  607.         mode->c_lflag |= ICANON;
  608.       else
  609.         mode->c_lflag &= ~ICANON;
  610.     }
  611.       else if (!strcmp (info->name, "pass8"))
  612.     {
  613.       if (reversed)
  614.         {
  615.           mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
  616.           mode->c_iflag |= ISTRIP;
  617.         }
  618.       else
  619.         {
  620.           mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  621.           mode->c_iflag &= ~ISTRIP;
  622.         }
  623.     }
  624.       else if (!strcmp (info->name, "litout"))
  625.     {
  626.       if (reversed)
  627.         {
  628.           mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
  629.           mode->c_iflag |= ISTRIP;
  630.           mode->c_oflag |= OPOST;
  631.         }
  632.       else
  633.         {
  634.           mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  635.           mode->c_iflag &= ~ISTRIP;
  636.           mode->c_oflag &= ~OPOST;
  637.         }
  638.     }
  639.       else if (!strcmp (info->name, "raw") || !strcmp (info->name, "cooked"))
  640.     {
  641.       if ((info->name[0] == 'r' && reversed)
  642.           || (info->name[0] == 'c' && !reversed))
  643.         {
  644.           /* Cooked mode. */
  645.           mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
  646.           mode->c_oflag |= OPOST;
  647.           mode->c_lflag |= ISIG | ICANON;
  648. #if VMIN == VEOF
  649.           mode->c_cc[VEOF] = CEOF;
  650. #endif
  651. #if VTIME == VEOL
  652.           mode->c_cc[VEOL] = CEOL;
  653. #endif
  654.         }
  655.       else
  656.         {
  657.           /* Raw mode. */
  658.           mode->c_iflag = 0;
  659.           mode->c_oflag &= ~OPOST;
  660.           mode->c_lflag &= ~(ISIG | ICANON
  661. #ifdef XCASE
  662.                  | XCASE
  663. #endif
  664.                  );
  665.           mode->c_cc[VMIN] = 1;
  666.           mode->c_cc[VTIME] = 0;
  667.         }
  668.     }
  669. #ifdef IXANY
  670.       else if (!strcmp (info->name, "decctlq"))
  671.     {
  672.       if (reversed)
  673.         mode->c_iflag |= IXANY;
  674.       else
  675.         mode->c_iflag &= ~IXANY;
  676.     }
  677. #endif
  678. #ifdef TABDLY
  679.       else if (!strcmp (info->name, "tabs"))
  680.     {
  681.       if (reversed)
  682.         mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
  683.       else
  684.         mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
  685.     }
  686. #endif
  687. #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
  688.       else if (!strcmp (info->name, "lcase")
  689.            || !strcmp (info->name, "LCASE"))
  690.     {
  691.       if (reversed)
  692.         {
  693.           mode->c_lflag &= ~XCASE;
  694.           mode->c_iflag &= ~IUCLC;
  695.           mode->c_oflag &= ~OLCUC;
  696.         }
  697.       else
  698.         {
  699.           mode->c_lflag |= XCASE;
  700.           mode->c_iflag |= IUCLC;
  701.           mode->c_oflag |= OLCUC;
  702.         }
  703.     }
  704. #endif
  705.       else if (!strcmp (info->name, "crt"))
  706.     mode->c_lflag |= ECHOE
  707. #ifdef ECHOCTL
  708.       | ECHOCTL
  709. #endif
  710. #ifdef ECHOKE
  711.         | ECHOKE
  712. #endif
  713.           ;
  714.       else if (!strcmp (info->name, "dec"))
  715.     {
  716.       mode->c_cc[VINTR] = 3; /* ^C */
  717.       mode->c_cc[VERASE] = 127; /* DEL */
  718.       mode->c_cc[VKILL] = 21; /* ^U */
  719.       mode->c_lflag |= ECHOE
  720. #ifdef ECHOCTL
  721.         | ECHOCTL
  722. #endif
  723. #ifdef ECHOKE
  724.           | ECHOKE
  725. #endif
  726.         ;
  727. #ifdef IXANY
  728.       mode->c_iflag &= ~IXANY;
  729. #endif
  730.     }
  731.     }
  732.   else if (reversed)
  733.     *bitsp = *bitsp & ~info->mask & ~info->bits;
  734.   else
  735.     *bitsp = (*bitsp & ~info->mask) | info->bits;
  736.  
  737.   return 1;
  738. }
  739.  
  740. void
  741. set_control_char (info, arg, mode)
  742.      struct control_info *info;
  743.      char *arg;
  744.      struct termios *mode;
  745. {
  746.   unsigned char value;
  747.  
  748.   if (!strcmp (info->name, "min") || !strcmp (info->name, "time"))
  749.     value = integer_arg (arg);
  750.   else if (arg[0] == '\0' || arg[1] == '\0')
  751.     value = arg[0];
  752.   else if (!strcmp (arg, "^-") || !strcmp (arg, "undef"))
  753.     value = _POSIX_VDISABLE;
  754.   else if (arg[0] == '^' && arg[1] != '\0')    /* Ignore any trailing junk. */
  755.     {
  756.       if (arg[1] == '?')
  757.     value = 127;
  758.       else
  759.     value = arg[1] & ~0140;    /* Non-letters get weird results. */
  760.     }
  761.   else
  762.     value = integer_arg (arg);
  763.   mode->c_cc[info->offset] = value;
  764. }
  765.  
  766. void
  767. set_speed (type, arg, mode)
  768.      enum speed_setting type;
  769.      char *arg;
  770.      struct termios *mode;
  771. {
  772.   speed_t baud;
  773.  
  774.   baud = string_to_baud (arg);
  775.   if (type == input_speed || type == both_speeds)
  776.     cfsetispeed (mode, baud);
  777.   if (type == output_speed || type == both_speeds)
  778.     cfsetospeed (mode, baud);
  779. }
  780.  
  781. #ifdef TIOCGWINSZ
  782. void
  783. set_window_size (rows, cols)
  784.      int rows, cols;
  785. {
  786.   struct winsize win;
  787.  
  788.   if (ioctl (0, TIOCGWINSZ, (char *) &win))
  789.     error (1, errno, "standard input");
  790.   if (rows >= 0)
  791.     win.ws_row = rows;
  792.   if (cols >= 0)
  793.     win.ws_col = cols;
  794.   if (ioctl (0, TIOCSWINSZ, (char *) &win))
  795.     error (1, errno, "standard input");
  796. }
  797.  
  798. void
  799. display_window_size (fancy)
  800.      int fancy;
  801. {
  802.   struct winsize win;
  803.  
  804.   if (ioctl (0, TIOCGWINSZ, (char *) &win))
  805.     error (1, errno, "standard input");
  806.   wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n", win.ws_row, win.ws_col);
  807.   if (!fancy)
  808.     current_col = 0;
  809. }
  810. #endif
  811.  
  812. int
  813. screen_columns ()
  814. {
  815. #ifdef TIOCGWINSZ
  816.   struct winsize win;
  817.  
  818.   if (ioctl (0, TIOCGWINSZ, (char *) &win))
  819.     error (1, errno, "standard input");
  820.   if (win.ws_col > 0)
  821.     return win.ws_col;
  822. #endif
  823.   if (getenv ("COLUMNS"))
  824.     return atoi (getenv ("COLUMNS"));
  825.   return 80;
  826. }
  827.  
  828. tcflag_t *
  829. mode_type_flag (type, mode)
  830.      enum mode_type type;
  831.      struct termios *mode;
  832. {
  833.   switch (type)
  834.     {
  835.     case control:
  836.       return &mode->c_cflag;
  837.  
  838.     case input:
  839.       return &mode->c_iflag;
  840.  
  841.     case output:
  842.       return &mode->c_oflag;
  843.  
  844.     case local:
  845.       return &mode->c_lflag;
  846.  
  847.     case combination:
  848.       return NULL;
  849.     }
  850. }
  851.  
  852. void
  853. display_settings (output_type, mode)
  854.      enum output_type output_type;
  855.      struct termios *mode;
  856. {
  857.   switch (output_type)
  858.     {
  859.     case changed:
  860.       display_changed (mode);
  861.       break;
  862.  
  863.     case all:
  864.       display_all (mode);
  865.       break;
  866.  
  867.     case recoverable:
  868.       display_recoverable (mode);
  869.       break;
  870.     }
  871. }
  872.  
  873. void
  874. display_changed (mode)
  875.      struct termios *mode;
  876. {
  877.   int i;
  878.   int empty_line;
  879.   tcflag_t *bitsp;
  880.   unsigned long mask;
  881.   enum mode_type prev_type = control;
  882.  
  883.   display_speed (mode, 1);
  884. #ifdef HAVE_C_LINE
  885.   wrapf ("line = %d;", mode->c_line);
  886. #endif
  887.   putchar ('\n');
  888.   current_col = 0;
  889.  
  890.   empty_line = 1;
  891.   for (i = 0; strcmp (control_info[i].name, "min"); ++i)
  892.     {
  893.       if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
  894.     continue;
  895.       empty_line = 0;
  896.       wrapf ("%s = %s;", control_info[i].name,
  897.          visible (mode->c_cc[control_info[i].offset]));
  898.     }
  899.   if ((mode->c_lflag & ICANON) == 0)
  900.     {
  901.       wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
  902.          (int) mode->c_cc[VTIME]);
  903.     }
  904.   else if (empty_line == 0)
  905.     putchar ('\n');
  906.   current_col = 0;
  907.  
  908.   empty_line = 1;
  909.   for (i = 0; mode_info[i].name != NULL; ++i)
  910.     {
  911.       if (mode_info[i].flags & OMIT)
  912.     continue;
  913.       if (mode_info[i].type != prev_type)
  914.     {
  915.       if (empty_line == 0)
  916.         {
  917.           putchar ('\n');
  918.           current_col = 0;
  919.           empty_line = 1;
  920.         }
  921.       prev_type = mode_info[i].type;
  922.     }
  923.  
  924.       bitsp = mode_type_flag (mode_info[i].type, mode);
  925.       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
  926.       if ((*bitsp & mask) == mode_info[i].bits)
  927.     {
  928.       if (mode_info[i].flags & SANE_UNSET)
  929.         {
  930.           wrapf ("%s", mode_info[i].name);
  931.           empty_line = 0;
  932.         }
  933.     }
  934.       else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
  935.     {
  936.       wrapf ("-%s", mode_info[i].name);
  937.       empty_line = 0;
  938.     }
  939.     }
  940.   if (empty_line == 0)
  941.     putchar ('\n');
  942.   current_col = 0;
  943. }
  944.  
  945. void
  946. display_all (mode)
  947.      struct termios *mode;
  948. {
  949.   int i;
  950.   tcflag_t *bitsp;
  951.   unsigned long mask;
  952.   enum mode_type prev_type = control;
  953.  
  954.   display_speed (mode, 1);
  955. #ifdef TIOCGWINSZ
  956.   display_window_size (1);
  957. #endif
  958. #ifdef HAVE_C_LINE
  959.   wrapf ("line = %d;", mode->c_line);
  960. #endif
  961.   putchar ('\n');
  962.   current_col = 0;
  963.  
  964.   for (i = 0; strcmp (control_info[i].name, "min"); ++i)
  965.     {
  966.       wrapf ("%s = %s;", control_info[i].name,
  967.          visible (mode->c_cc[control_info[i].offset]));
  968.     }
  969.   wrapf ("min = %d; time = %d;\n", mode->c_cc[VMIN], mode->c_cc[VTIME]);
  970.   current_col = 0;
  971.  
  972.   for (i = 0; mode_info[i].name != NULL; ++i)
  973.     {
  974.       if (mode_info[i].flags & OMIT)
  975.     continue;
  976.       if (mode_info[i].type != prev_type)
  977.     {
  978.       putchar ('\n');
  979.       current_col = 0;
  980.       prev_type = mode_info[i].type;
  981.     }
  982.  
  983.       bitsp = mode_type_flag (mode_info[i].type, mode);
  984.       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
  985.       if ((*bitsp & mask) == mode_info[i].bits)
  986.     wrapf ("%s", mode_info[i].name);
  987.       else if (mode_info[i].flags & REV)
  988.     wrapf ("-%s", mode_info[i].name);
  989.     }
  990.   putchar ('\n');
  991.   current_col = 0;
  992. }
  993.  
  994. void
  995. display_speed (mode, fancy)
  996.      struct termios *mode;
  997.      int fancy;
  998. {
  999.   if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
  1000.     wrapf (fancy ? "speed %lu baud;" : "%lu\n",
  1001.        baud_to_value (cfgetospeed (mode)));
  1002.   else
  1003.     wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
  1004.        baud_to_value (cfgetispeed (mode)),
  1005.        baud_to_value (cfgetospeed (mode)));
  1006.   if (!fancy)
  1007.     current_col = 0;
  1008. }
  1009.  
  1010. void
  1011. display_recoverable (mode)
  1012.      struct termios *mode;
  1013. {
  1014.   int i;
  1015.  
  1016.   printf ("%lx:%lx:%lx:%lx",
  1017.       (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
  1018.       (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
  1019.   for (i = 0; i < NCCS; ++i)
  1020.     printf (":%x", (unsigned int) mode->c_cc[i]);
  1021.   putchar ('\n');
  1022. }
  1023.  
  1024. int
  1025. recover_mode (arg, mode)
  1026.      char *arg;
  1027.      struct termios *mode;
  1028. {
  1029.   int i, n;
  1030.   unsigned int chr;
  1031.   unsigned long iflag, oflag, cflag, lflag;
  1032.  
  1033.   /* Scan into temporaries since it is too much trouble to figure out
  1034.      the right format for `tcflag_t'.  */
  1035.   if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
  1036.           &iflag, &oflag, &cflag, &lflag, &n) != 4)
  1037.     return 0;
  1038.   mode->c_iflag = iflag;
  1039.   mode->c_oflag = oflag;
  1040.   mode->c_cflag = cflag;
  1041.   mode->c_lflag = lflag;
  1042.   arg += n;
  1043.   for (i = 0; i < NCCS; ++i)
  1044.     {
  1045.       if (sscanf (arg, ":%x%n", &chr, &n) != 1)
  1046.     return 0;
  1047.       mode->c_cc[i] = chr;
  1048.       arg += n;
  1049.     }
  1050.   return 1;
  1051. }
  1052.  
  1053. struct speed_map
  1054. {
  1055.   char *string;            /* ASCII representation. */
  1056.   speed_t speed;        /* Internal form. */
  1057.   unsigned long value;        /* Numeric value. */
  1058. };
  1059.  
  1060. struct speed_map speeds[] =
  1061. {
  1062.   {"0", B0, 0},
  1063.   {"50", B50, 50},
  1064.   {"75", B75, 75},
  1065.   {"110", B110, 110},
  1066.   {"134", B134, 134},
  1067.   {"134.5", B134, 134},
  1068.   {"150", B150, 150},
  1069.   {"200", B200, 200},
  1070.   {"300", B300, 300},
  1071.   {"600", B600, 600},
  1072.   {"1200", B1200, 1200},
  1073.   {"1800", B1800, 1800},
  1074.   {"2400", B2400, 2400},
  1075.   {"4800", B4800, 4800},
  1076.   {"9600", B9600, 9600},
  1077.   {"19200", B19200, 19200},
  1078.   {"38400", B38400, 38400},
  1079.   {"exta", B19200, 19200},
  1080.   {"extb", B38400, 38400},
  1081. #ifdef B57600
  1082.   {"57600", B57600, 57600},
  1083. #endif
  1084. #ifdef B115200
  1085.   {"115200", B115200, 115200},
  1086. #endif
  1087.   {NULL, 0, 0}
  1088. };
  1089.  
  1090. speed_t
  1091. string_to_baud (arg)
  1092.      char *arg;
  1093. {
  1094.   int i;
  1095.  
  1096.   for (i = 0; speeds[i].string != NULL; ++i)
  1097.     if (!strcmp (arg, speeds[i].string))
  1098.       return speeds[i].speed;
  1099.   return (speed_t) -1;
  1100. }
  1101.  
  1102. unsigned long
  1103. baud_to_value (speed)
  1104.      speed_t speed;
  1105. {
  1106.   int i;
  1107.  
  1108.   for (i = 0; speeds[i].string != NULL; ++i)
  1109.     if (speed == speeds[i].speed)
  1110.       return speeds[i].value;
  1111.   return 0;
  1112. }
  1113.  
  1114. void
  1115. sane_mode (mode)
  1116.      struct termios *mode;
  1117. {
  1118.   int i;
  1119.   tcflag_t *bitsp;
  1120.  
  1121.   for (i = 0; control_info[i].name; ++i)
  1122.     {
  1123. #if VMIN == VEOF
  1124.       if (!strcmp (control_info[i].name, "min"))
  1125.     break;
  1126. #endif
  1127.       mode->c_cc[control_info[i].offset] = control_info[i].saneval;
  1128.     }
  1129.  
  1130.   for (i = 0; mode_info[i].name != NULL; ++i)
  1131.     {
  1132.       if (mode_info[i].flags & SANE_SET)
  1133.     {
  1134.       bitsp = mode_type_flag (mode_info[i].type, mode);
  1135.       *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
  1136.     }
  1137.       else if (mode_info[i].flags & SANE_UNSET)
  1138.     {
  1139.       bitsp = mode_type_flag (mode_info[i].type, mode);
  1140.       *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
  1141.     }
  1142.     }
  1143. }
  1144.  
  1145. /* Return a string that is the printable representation of character CH.  */
  1146. /* Adapted from `cat' by Torbjorn Granlund.  */
  1147.  
  1148. char *
  1149. visible (ch)
  1150.      unsigned char ch;
  1151. {
  1152.   static char buf[10];
  1153.   char *bpout = buf;
  1154.  
  1155.   if (ch == _POSIX_VDISABLE)
  1156.     return "<undef>";
  1157.  
  1158.   if (ch >= 32)
  1159.     {
  1160.       if (ch < 127)
  1161.     *bpout++ = ch;
  1162.       else if (ch == 127)
  1163.     {
  1164.       *bpout++ = '^';
  1165.       *bpout++ = '?';
  1166.     }
  1167.       else
  1168.     {
  1169.       *bpout++ = 'M',
  1170.         *bpout++ = '-';
  1171.       if (ch >= 128 + 32)
  1172.         {
  1173.           if (ch < 128 + 127)
  1174.         *bpout++ = ch - 128;
  1175.           else
  1176.         {
  1177.           *bpout++ = '^';
  1178.           *bpout++ = '?';
  1179.         }
  1180.         }
  1181.       else
  1182.         {
  1183.           *bpout++ = '^';
  1184.           *bpout++ = ch - 128 + 64;
  1185.         }
  1186.     }
  1187.     }
  1188.   else
  1189.     {
  1190.       *bpout++ = '^';
  1191.       *bpout++ = ch + 64;
  1192.     }
  1193.   *bpout = '\0';
  1194.   return buf;
  1195. }
  1196.  
  1197. /* Parse string S as an integer, using decimal radix by default,
  1198.    but allowing octal and hex numbers as in C.  */
  1199. /* From `od' by Richard Stallman.  */
  1200.  
  1201. long
  1202. integer_arg (s)
  1203.      char *s;
  1204. {
  1205.   long value;
  1206.   int radix = 10;
  1207.   char *p = s;
  1208.   int c;
  1209.  
  1210.   if (*p != '0')
  1211.     radix = 10;
  1212.   else if (*++p == 'x')
  1213.     {
  1214.       radix = 16;
  1215.       p++;
  1216.     }
  1217.   else
  1218.     radix = 8;
  1219.  
  1220.   value = 0;
  1221.   while (((c = *p++) >= '0' && c <= '9')
  1222.      || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
  1223.     {
  1224.       value *= radix;
  1225.       if (c >= '0' && c <= '9')
  1226.     value += c - '0';
  1227.       else
  1228.     value += (c & ~40) - 'A';
  1229.     }
  1230.  
  1231.   if (c == 'b')
  1232.     value *= 512;
  1233.   else if (c == 'B')
  1234.     value *= 1024;
  1235.   else
  1236.     p--;
  1237.  
  1238.   if (*p)
  1239.     error (1, 0, "invalid integer argument `%s'", s);
  1240.   return value;
  1241. }
  1242.